/**
 * ObjectIdentifier
 *
 * An ASN1 type for an ObjectIdentifier
 * We store the oid in an Array.
 * Copyright (c) 2007 Henri Torgemane
 *
 * See LICENSE.txt for full license information.
 */
package com.hurlant.util.der
{
	import flash.utils.ByteArray;

	public class ObjectIdentifier implements IAsn1Type
	{
		private var type:uint;
		private var len:uint;
		private var oid:Array;

		public function ObjectIdentifier(type:uint, length:uint, b:*)
		{
			this.type=type;
			this.len=length;
			if (b is ByteArray)
			{
				parse(b as ByteArray);
			}
			else if (b is String)
			{
				generate(b as String);
			}
			else
			{
				throw new Error("Invalid call to new ObjectIdentifier");
			}
		}

		private function generate(s:String):void
		{
			oid=s.split(".");
		}

		private function parse(b:ByteArray):void
		{
			// parse stuff
			// first byte = 40*value1 + value2
			var o:uint=b.readUnsignedByte();
			var a:Array=[]
			a.push(uint(o / 40));
			a.push(uint(o % 40));
			var v:uint=0;
			while (b.bytesAvailable > 0)
			{
				o=b.readUnsignedByte();
				var last:Boolean=(o & 0x80) == 0;
				o&=0x7f;
				v=v * 128 + o;
				if (last)
				{
					a.push(v);
					v=0;
				}
			}
			oid=a;
		}

		public function getLength():uint
		{
			return len;
		}

		public function getType():uint
		{
			return type;
		}

		public function toDER():ByteArray
		{
			var tmp:Array=[];
			tmp[0]=oid[0] * 40 + oid[1];
			for (var i:int=2; i < oid.length; i++)
			{
				var v:int=parseInt(oid[i]);
				if (v < 128)
				{
					tmp.push(v);
				}
				else if (v < 128 * 128)
				{
					tmp.push((v >> 7) | 0x80);
					tmp.push(v & 0x7f);
				}
				else if (v < 128 * 128 * 128)
				{
					tmp.push((v >> 14) | 0x80);
					tmp.push((v >> 7) & 0x7f | 0x80);
					tmp.push(v & 0x7f);
				}
				else if (v < 128 * 128 * 128 * 128)
				{
					tmp.push((v >> 21) | 0x80);
					tmp.push((v >> 14) & 0x7f | 0x80);
					tmp.push((v >> 7) & 0x7f | 0x80);
					tmp.push(v & 0x7f);
				}
				else
				{
					throw new Error("OID element bigger than we thought. :(");
				}
			}
			len=tmp.length;
			if (type == 0)
			{
				type=6;
			}
			tmp.unshift(len); // assume length is small enough to fit here.
			tmp.unshift(type);
			var b:ByteArray=new ByteArray;
			for (i=0; i < tmp.length; i++)
			{
				b[i]=tmp[i];
			}
			return b;
		}

		public function toString():String
		{
			return DER.indent + oid.join(".");
		}

		public function dump():String
		{
			return "OID[" + type + "][" + len + "][" + toString() + "]";
		}

	}
}

